home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1999 #2 / Amiga Plus CD - 1999 - No. 2.iso / System-Boost / Workbench / ToolManager / Source / Library / group.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  14KB  |  521 lines

  1. /*
  2.  * group.c  V3.1
  3.  *
  4.  * ToolManager group gadget class
  5.  *
  6.  * Copyright (C) 1990-98 Stefan Becker
  7.  *
  8.  * This source code is for educational purposes only. You may study it
  9.  * and copy ideas or algorithms from it for your own projects. It is
  10.  * not allowed to use any of the source codes (in full or in parts)
  11.  * in other programs. Especially it is not allowed to create variants
  12.  * of ToolManager or ToolManager-like programs from this source code.
  13.  *
  14.  */
  15.  
  16. #include "toolmanager.h"
  17.  
  18. /* Group class instance data */
  19. struct GroupClassData {
  20.  struct MinList  gcd_Gadgets;
  21.  ULONG           gcd_MaxWidth;
  22.  ULONG           gcd_MaxHeight;
  23.  Object         *gcd_Active;
  24.  UWORD           gcd_ActiveX;
  25.  UWORD           gcd_ActiveY;
  26. };
  27. #define TYPED_INST_DATA(cl, o) ((struct GroupClassData *) INST_DATA((cl), (o)))
  28. #define GADGET(g)              ((struct Gadget *) (g))
  29.  
  30. /* Group class method: GM_HITTEST */
  31. #undef  DEBUGFUNCTION
  32. #define DEBUGFUNCTION GroupClassHitTest
  33. static ULONG GroupClassHitTest(Class *cl, Object *obj, struct gpHitTest *gpht)
  34. {
  35.  struct GroupClassData *gcd  = TYPED_INST_DATA(cl, obj);
  36.  Object                *obj1 = (Object *) gcd->gcd_Gadgets.mlh_Head;
  37.  UWORD                  x    = gpht->gpht_Mouse.X + GADGET(obj)->LeftEdge;
  38.  UWORD                  y    = gpht->gpht_Mouse.Y + GADGET(obj)->TopEdge;
  39.  struct Gadget         *g;
  40.  
  41.  GROUPCLASS_LOG(LOG2(Mouse, "X %ld Y %ld", x, y))
  42.  
  43.  /* Scan object list */
  44.  while (g = GADGET(NextObject(&obj1))) {
  45.  
  46.   /* Calculate new coordinates relative to gadget */
  47.   gpht->gpht_Mouse.X = x - g->LeftEdge;
  48.   gpht->gpht_Mouse.Y = y - g->TopEdge;
  49.  
  50.   /* Send message to gadget */
  51.   if (DoMethodA((Object *) g, (Msg) gpht) == GMR_GADGETHIT) break;
  52.  }
  53.  
  54.  GROUPCLASS_LOG(LOG1(Gadget, "0x%08lx", g))
  55.  
  56.  /* Save active gadget */
  57.  gcd->gcd_Active = (Object *) g;
  58.  
  59.  /* Active gadget found? */
  60.  return(g ? GMR_GADGETHIT : 0);
  61. }
  62.  
  63. /* Group class method: GM_RENDER */
  64. #undef  DEBUGFUNCTION
  65. #define DEBUGFUNCTION GroupClassRender
  66. static ULONG GroupClassRender(Class *cl, Object *obj, Msg msg)
  67. {
  68.  Object *obj1 = (Object *) TYPED_INST_DATA(cl, obj)->gcd_Gadgets.mlh_Head;
  69.  Object *obj2;
  70.  
  71.  GROUPCLASS_LOG(LOG0(Rendering))
  72.  
  73.  /* Scan object list and forward message to objects */
  74.  while (obj2 = NextObject(&obj1)) DoMethodA(obj2, msg);
  75.  
  76.  /* Return 1 to indicate that the method is implemented */
  77.  return(1);
  78. }
  79.  
  80. /* Send a translated gpInput method to gadget */
  81. static ULONG DoTranslatedMethod(struct GroupClassData *gcd, Object *obj,
  82.                                 struct gpInput *gpi)
  83. {
  84.  /* Correct coordinates */
  85.  gpi->gpi_Mouse.X -= gcd->gcd_ActiveX;
  86.  gpi->gpi_Mouse.Y -= gcd->gcd_ActiveY;
  87.  
  88.  /* Forward method to active gadget */
  89.  return(DoMethodA(obj, (Msg) gpi));
  90. }
  91.  
  92. /* Group class method: GM_GOACTIVE */
  93. #undef  DEBUGFUNCTION
  94. #define DEBUGFUNCTION GroupClassGoActive
  95. static ULONG GroupClassGoActive(Class *cl, Object *obj, struct gpInput *gpi)
  96. {
  97.  struct GroupClassData *gcd = TYPED_INST_DATA(cl, obj);
  98.  struct Gadget         *g   = GADGET(gcd->gcd_Active);
  99.  ULONG                  rc  = GMR_REUSE;
  100.  
  101.  GROUPCLASS_LOG(LOG0(Go Active))
  102.  
  103.  /* Active gadget valid? */
  104.  if (g) {
  105.  
  106.   /* Save active gadgets offsets (Gadget coord. are relative to window!) */
  107.   gcd->gcd_ActiveX = g->LeftEdge - GADGET(obj)->LeftEdge;
  108.   gcd->gcd_ActiveY = g->TopEdge  - GADGET(obj)->TopEdge;
  109.  
  110.   /* Forward method to active gadget */
  111.   rc = DoTranslatedMethod(gcd, (Object *) g, gpi);
  112.  }
  113.  
  114.  GROUPCLASS_LOG(LOG1(Result, "0x%08lx", rc))
  115.  
  116.  return(rc);
  117. }
  118.  
  119. /* Group class method: GM_HANDLEINPUT */
  120. #undef  DEBUGFUNCTION
  121. #define DEBUGFUNCTION GroupClassHandleInput
  122. static ULONG GroupClassHandleInput(Class *cl, Object *obj,
  123.                                    struct gpInput *gpi)
  124. {
  125.  struct GroupClassData *gcd = TYPED_INST_DATA(cl, obj);
  126.  ULONG                  rc  = GMR_REUSE;
  127.  
  128.  GROUPCLASS_LOG(LOG0(Handle Input))
  129.  
  130.  /* Active gadget valid? */
  131.  if (gcd->gcd_Active)
  132.  
  133.   /* Forward method to active gadget */
  134.   if ((rc = DoTranslatedMethod(gcd, gcd->gcd_Active, gpi)) & GMR_VERIFY) {
  135.  
  136.    GROUPCLASS_LOG(LOG1(Gadget released, "%ld",
  137.                        GADGET(gcd->gcd_Active)->GadgetID))
  138.  
  139.    /* Copy the gadget ID to the termination field */
  140.    *gpi->gpi_Termination = GADGET(gcd->gcd_Active)->GadgetID;
  141.   }
  142.  
  143.  return(rc);
  144. }
  145.  
  146. /* Group class method: GM_GOINACTIVE */
  147. #undef  DEBUGFUNCTION
  148. #define DEBUGFUNCTION GroupClassGoInactive
  149. static ULONG GroupClassGoInactive(Class *cl, Object *obj, Msg msg)
  150. {
  151.  struct GroupClassData *gcd = TYPED_INST_DATA(cl, obj);
  152.  
  153.  GROUPCLASS_LOG(LOG0(Go Inactive))
  154.  
  155.  /* Active gadget valid? */
  156.  if (gcd->gcd_Active) {
  157.  
  158.   /* Forward method to active gadget */
  159.   DoMethodA(gcd->gcd_Active, msg);
  160.  
  161.   /* Clear active gadget*/
  162.   gcd->gcd_Active = NULL;
  163.  }
  164.  
  165.  /* Return 1 to indicate that the method is implemented */
  166.  return(1);
  167. }
  168.  
  169. /* Group class method: OM_NEW */
  170. #undef  DEBUGFUNCTION
  171. #define DEBUGFUNCTION GroupClassNew
  172. static ULONG GroupClassNew(Class *cl, Object *obj, struct opSet *ops)
  173. {
  174.  GROUPCLASS_LOG((LOG1(Tags, "0x%08lx", ops->ops_AttrList),
  175.                 PrintTagList(ops->ops_AttrList)))
  176.  
  177.  /* Call SuperClass */
  178.  if (obj = (Object *) DoSuperMethodA(cl, obj, (Msg) ops)) {
  179.   struct GroupClassData *gcd = TYPED_INST_DATA(cl, obj);
  180.  
  181.   /* Initalize instance data */
  182.   gcd->gcd_MaxWidth  = 0;
  183.   gcd->gcd_MaxHeight = 0;
  184.   gcd->gcd_Active    = NULL;
  185.  
  186.   /* Initialize gadget list */
  187.   NewList((struct List *) &gcd->gcd_Gadgets);
  188.  }
  189.  
  190.  return((ULONG) obj);
  191. }
  192.  
  193. /* Group class method: OM_DISPOSE */
  194. #undef  DEBUGFUNCTION
  195. #define DEBUGFUNCTION GroupClassDispose
  196. static ULONG GroupClassDispose(Class *cl, Object *obj, Msg msg)
  197. {
  198.  Object *obj1 = (Object *) TYPED_INST_DATA(cl, obj)->gcd_Gadgets.mlh_Head;
  199.  Object *obj2;
  200.  
  201.  GROUPCLASS_LOG(LOG0(Disposing))
  202.  
  203.  /* Scan object list and delete objects */
  204.  while (obj2 = NextObject(&obj1)) {
  205.  
  206.   /* Remove object */
  207.   DoMethod(obj2, OM_REMOVE);
  208.  
  209.   /* Dispose object */
  210.   DisposeObject(obj2);
  211.  }
  212.  
  213.  /* Call SuperClass */
  214.  return(DoSuperMethodA(cl, obj, msg));
  215. }
  216.  
  217. /* Group class method: OM_SET */
  218. #undef  DEBUGFUNCTION
  219. #define DEBUGFUNCTION GroupClassSet
  220. static ULONG GroupClassSet(Class *cl, Object *obj, struct opSet *ops)
  221. {
  222.  struct TagItem *tstate = ops->ops_AttrList;
  223.  struct TagItem *ti;
  224.  
  225.  GROUPCLASS_LOG((LOG1(Tags, "0x%08lx", ops->ops_AttrList),
  226.                  PrintTagList(ops->ops_AttrList)))
  227.  
  228.  /* Scan tag list */
  229.  while (ti = NextTagItem(&tstate))
  230.  
  231.   /* Which attribute shall be set? */
  232.   switch (ti->ti_Tag) {
  233.    case GA_Left: {
  234.      Object        *obj1  = (Object *)
  235.                              TYPED_INST_DATA(cl, obj)->gcd_Gadgets.mlh_Head;
  236.      struct Gadget *g;
  237.      ULONG          delta = ti->ti_Data - GADGET(obj)->LeftEdge;
  238.  
  239.      /* Scan object list */
  240.      while (g = GADGET(NextObject(&obj1)))
  241.  
  242.       /* Set new X coordinate */
  243.       SetGadgetAttrs(g, ops->ops_GInfo->gi_Window,
  244.                         ops->ops_GInfo->gi_Requester,
  245.                         GA_Left, g->LeftEdge + delta,
  246.                         TAG_DONE);
  247.  
  248.      /* Set new X coordinate */
  249.      GADGET(obj)->LeftEdge = ti->ti_Data;
  250.     }
  251.     break;
  252.  
  253.    case GA_Top: {
  254.      Object        *obj1  = (Object *)
  255.                              TYPED_INST_DATA(cl, obj)->gcd_Gadgets.mlh_Head;
  256.      struct Gadget *g;
  257.      ULONG          delta = ti->ti_Data - GADGET(obj)->TopEdge;
  258.  
  259.      /* Scan object list */
  260.      while (g = GADGET(NextObject(&obj1)))
  261.  
  262.       /* Set new X coordinate */
  263.       SetGadgetAttrs(g, ops->ops_GInfo->gi_Window,
  264.                         ops->ops_GInfo->gi_Requester,
  265.                         GA_Top, g->TopEdge + delta,
  266.                         TAG_DONE);
  267.  
  268.      /* Set new X coordinate */
  269.      GADGET(obj)->TopEdge = ti->ti_Data;
  270.     }
  271.     break;
  272.   }
  273.  
  274.  /* Call SuperClass */
  275.  return(DoSuperMethodA(cl, obj, (Msg) ops));
  276. }
  277.  
  278. /* Group class method: OM_ADDMEMBER */
  279. #undef  DEBUGFUNCTION
  280. #define DEBUGFUNCTION GroupClassAddMember
  281. static ULONG GroupClassAddMember(Class *cl, Object *obj, struct opMember *opm)
  282. {
  283.  struct GroupClassData *gcd = TYPED_INST_DATA(cl, obj);
  284.  struct Gadget         *g   = GADGET(opm->opam_Object);
  285.  
  286.  /* Check gadget size and correct limits */
  287.  if (g->Width  > gcd->gcd_MaxWidth)  gcd->gcd_MaxWidth  = g->Width;
  288.  if (g->Height > gcd->gcd_MaxHeight) gcd->gcd_MaxHeight = g->Height;
  289.  
  290.  /* Let the object handle the adding */
  291.  return(DoMethod((Object *) g, OM_ADDTAIL, &gcd->gcd_Gadgets));
  292. }
  293.  
  294. /* Group class method: TMM_Layout */
  295. #undef  DEBUGFUNCTION
  296. #define DEBUGFUNCTION GroupClassLayout
  297. static ULONG GroupClassLayout(Class *cl, Object *obj, struct TMP_Layout *tmpl)
  298. {
  299.  ULONG entries = 0;
  300.  
  301.  GROUPCLASS_LOG(LOG1(Columns, "%ld", tmpl->tmpl_Columns))
  302.  
  303.  /* Sanity check! */
  304.  if (tmpl->tmpl_Columns != 0) {
  305.   struct GroupClassData *gcd   = TYPED_INST_DATA(cl, obj);
  306.   Object                *obj1  = (Object *) gcd->gcd_Gadgets.mlh_Head;
  307.   struct Gadget         *g;
  308.   ULONG                  x     = GADGET(obj)->LeftEdge;
  309.   ULONG                  y     = GADGET(obj)->TopEdge;
  310.   ULONG                  cols  = 0;
  311.  
  312.   GROUPCLASS_LOG(LOG2(Box, "Width %ld Height %ld", gcd->gcd_MaxWidth,
  313.                       gcd->gcd_MaxHeight))
  314.  
  315.   /* Scan object list */
  316.   while (g = GADGET(NextObject(&obj1))) {
  317.  
  318.    /* Increment counter */
  319.    entries++;
  320.  
  321.    /* Set X & Y and ID for the gadget */
  322.    SetGadgetAttrs(g, NULL, NULL, GA_Left,   x,
  323.                                  GA_Top,    y,
  324.                                  GA_Width,  gcd->gcd_MaxWidth,
  325.                                  GA_Height, gcd->gcd_MaxHeight,
  326.                                  GA_ID,     entries,
  327.                                  TAG_DONE);
  328.  
  329.    /* Correct counters */
  330.    if (++cols >= tmpl->tmpl_Columns) {
  331.  
  332.     /* Column full, reset X & column counter and increment Y & row counter */
  333.     x     = GADGET(obj)->LeftEdge;
  334.     y    += gcd->gcd_MaxHeight;
  335.     cols  = 0;
  336.  
  337.    } else
  338.  
  339.     /* Column not yet full, just increment X */
  340.     x += gcd->gcd_MaxWidth;
  341.   }
  342.  
  343.   /* Calculate new gadget hit box */
  344.   GADGET(obj)->Width  = gcd->gcd_MaxWidth  * tmpl->tmpl_Columns;
  345.   GADGET(obj)->Height = gcd->gcd_MaxHeight *
  346.                      ((entries + tmpl->tmpl_Columns - 1) / tmpl->tmpl_Columns);
  347.  }
  348.  
  349.  GROUPCLASS_LOG(LOG3(Result, "Entries %ld Width %ld Height %ld", entries,
  350.                      GADGET(obj)->Width, GADGET(obj)->Height))
  351.  
  352.  /* Return FALSE if no objects are in the group */
  353.  return(entries != 0);
  354. }
  355.  
  356. /* Group class method: TMM_GadgetUp */
  357. #undef  DEBUGFUNCTION
  358. #define DEBUGFUNCTION GroupClassGadgetUp
  359. static ULONG GroupClassGadgetUp(Class *cl, Object *obj,
  360.                                 struct TMP_GadgetUp *tmpgu)
  361. {
  362.  Object        *obj1 = (Object *)
  363.                         TYPED_INST_DATA(cl, obj)->gcd_Gadgets.mlh_Head;
  364.  struct Gadget *g;
  365.  
  366.  GROUPCLASS_LOG(LOG1(GadgetID, "%ld", tmpgu->tmpgu_GadgetID))
  367.  
  368.  /* Scan object list */
  369.  while (g = GADGET(NextObject(&obj1))) {
  370.  
  371.   GROUPCLASS_LOG(LOG1(Gadget, "0x%08lx", g))
  372.  
  373.   /* Gadget found? */
  374.   if (g->GadgetID == tmpgu->tmpgu_GadgetID) {
  375.  
  376.    GROUPCLASS_LOG(LOG0(Activating gadget))
  377.  
  378.    /* Send activate message to gadget */
  379.    DoMethod((Object *) g, TMM_Activate, NULL);
  380.  
  381.    /* Leave loop */
  382.    break;
  383.   }
  384.  }
  385.  
  386.  /* Return 1 to indicate that the method is implemented */
  387.  return(1);
  388. }
  389.  
  390. /* Group class method: TMM_AppEvent */
  391. #undef  DEBUGFUNCTION
  392. #define DEBUGFUNCTION GroupClassAppEvent
  393. static ULONG GroupClassAppEvent(Class *cl, Object *obj,
  394.                                 struct TMP_AppEvent *tmpae)
  395. {
  396.  struct GroupClassData *gcd  = TYPED_INST_DATA(cl, obj);
  397.  Object                *obj1 = (Object *) gcd->gcd_Gadgets.mlh_Head;
  398.  WORD                   x    = tmpae->tmpae_Message->am_MouseX;
  399.  WORD                   y    = tmpae->tmpae_Message->am_MouseY;
  400.  struct Gadget         *g;
  401.  struct gpHitTest       gpht = { GM_HITTEST, NULL };
  402.  
  403.  GROUPCLASS_LOG(LOG2(Mouse, "X %ld Y %ld", x, y))
  404.  
  405.  /* Scan object list */
  406.  while (g = GADGET(NextObject(&obj1))) {
  407.  
  408.   /* Calculate coordinates relative to the gadget */
  409.   gpht.gpht_Mouse.X = x - g->LeftEdge;
  410.   gpht.gpht_Mouse.Y = y - g->TopEdge;
  411.  
  412.   GROUPCLASS_LOG(LOG3(Gadget, "0x%08lx Relative X %ld Y %ld", g,
  413.                       gpht.gpht_Mouse.X, gpht.gpht_Mouse.Y))
  414.  
  415.   /* Send HITTEST message to gadget */
  416.   if (DoMethodA((Object *) g, (Msg) &gpht) == GMR_GADGETHIT)
  417.  
  418.    /* Gadget has been found */
  419.    break;
  420.  }
  421.  
  422.  GROUPCLASS_LOG(LOG1(Gadget, "0x%08lx", g))
  423.  
  424.  /* Send activate message to object */
  425.  if (g) DoMethod((Object *) g, TMM_Activate, tmpae->tmpae_Message);
  426.  
  427.  /* Return 1 to indicate that the method is implemented */
  428.  return(1);
  429. }
  430.  
  431. /* Group class dispatcher */
  432. #undef  DEBUGFUNCTION
  433. #define DEBUGFUNCTION GroupClassDispatcher
  434. static __geta4 ULONG GroupClassDispatcher(__A0 Class *cl, __A2 Object *obj,
  435.                                           __A1 Msg msg)
  436. {
  437.  ULONG rc;
  438.  
  439.  GROUPCLASS_LOG(LOG3(Arguments, "Class 0x%08lx Object 0x%08lx Msg 0x%08lx",
  440.                      cl, obj, msg))
  441.  
  442.  switch(msg->MethodID) {
  443.   /* BOOPSI gadget methods */
  444.   case GM_HITTEST:
  445.    rc = GroupClassHitTest(cl, obj, (struct gpHitTest *) msg);
  446.    break;
  447.  
  448.   case GM_RENDER:
  449.    rc = GroupClassRender(cl, obj, msg);
  450.    break;
  451.  
  452.   case GM_GOACTIVE:
  453.    rc = GroupClassGoActive(cl, obj, (struct gpInput *) msg);
  454.    break;
  455.  
  456.   case GM_HANDLEINPUT:
  457.    rc = GroupClassHandleInput(cl, obj, (struct gpInput *) msg);
  458.    break;
  459.  
  460.   case GM_GOINACTIVE:
  461.    rc = GroupClassGoInactive(cl, obj, msg);
  462.    break;
  463.  
  464.   /* BOOPSI methods */
  465.   case OM_NEW:
  466.    rc = GroupClassNew(cl, obj, (struct opSet *) msg);
  467.    break;
  468.  
  469.   case OM_DISPOSE:
  470.    rc = GroupClassDispose(cl, obj, msg);
  471.    break;
  472.  
  473.   case OM_SET:
  474.    rc = GroupClassSet(cl, obj, (struct opSet *) msg);
  475.    break;
  476.  
  477.   case OM_ADDMEMBER:
  478.    rc = GroupClassAddMember(cl, obj, (struct opMember *) msg);
  479.    break;
  480.  
  481.   /* TM methods */
  482.   case TMM_Layout:
  483.    rc = GroupClassLayout(cl, obj, (struct TMP_Layout *) msg);
  484.    break;
  485.  
  486.   case TMM_GadgetUp:
  487.    rc = GroupClassGadgetUp(cl, obj, (struct TMP_GadgetUp *) msg);
  488.    break;
  489.  
  490.   case TMM_AppEvent:
  491.    rc = GroupClassAppEvent(cl, obj, (struct TMP_AppEvent *) msg);
  492.    break;
  493.  
  494.   /* Unknown method -> delegate to SuperClass */
  495.   default:
  496.    rc = DoSuperMethodA(cl, obj, msg);
  497.    break;
  498.  }
  499.  
  500.  return(rc);
  501. }
  502.  
  503. /* Create base class */
  504. #undef  DEBUGFUNCTION
  505. #define DEBUGFUNCTION CreateGroupClass
  506. const Class *CreateGroupClass(void)
  507. {
  508.  Class *cl;
  509.  
  510.  /* Create class */
  511.  if (cl = MakeClass(NULL, GADGETCLASS, NULL, sizeof(struct GroupClassData), 0))
  512.  
  513.   /* Set dispatcher */
  514.   cl->cl_Dispatcher.h_Entry = (ULONG (*)()) GroupClassDispatcher;
  515.  
  516.  GROUPCLASS_LOG(LOG1(Class, "0x%08lx", cl))
  517.  
  518.  /* Return pointer to class */
  519.  return(cl);
  520. }
  521.